<?php

namespace App\Exceptions;

use App\Library\Ding\Ding;
use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Support\Facades\App;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * Description:将异常传递给记录异常的基类
     * Author: Sam
     * DateTime: 2018/12/24 13:11
     * @param Exception $exception
     * @return mixed|void
     * @throws Exception
     */
    public function report(Exception $exception)
    {
        parent::report($exception);
    }

    /**
     * Description:拦截各种异常
     * Author: Sam
     * DateTime: 2018/12/27 14:52
     * @param \Illuminate\Http\Request $request
     * @param Exception $exception
     * @return \Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
     * @throws Exception
     */
    public function render($request, Exception $exception)
    {
        if(
            $exception instanceof AuthenticationException
            ||
            $exception instanceof UnauthorizedHttpException
            ||
            $exception instanceof ValidationException
            ||
            $exception instanceof GeneralException
            ||
            $exception instanceof ModelNotFoundException
            ||
            $exception instanceof ThrottleRequestsException
        )
        {
            /**
             * 拦截主动抛出的异常
             */
            if($exception instanceof GeneralException){
                if(substr($request->getPathInfo(),0,16)==='/api/source/r360'){
                    return r360fail($exception->getMessage());
                }
                return failed($exception->getMessage());
            }

            /**
             * 拦截404异常
             */
            if ($exception instanceof ModelNotFoundException) {
                return failed('资源不存在');
            }
            /**
             * 拦截授权异常
             */
            if ($exception instanceof AuthorizationException) {
                return failed('您无权访问', 403);
            }

            /**
             * 拦截参数错误异常
             */
            if ($exception instanceof ValidationException) {
                return failed(array_first(array_collapse($exception->errors())));
            }

            /**
             * 拦截用户认证异常 返回401
             */
            if ($exception instanceof UnauthorizedHttpException) {
                return failed('未提供Token', 401);
            }

            /**
             * 拦截用户token失效
             */
            if($exception instanceof AuthenticationException){
                return failed('认证失败,请您重新登录', 401);
            }

            /**
             * 拦截请求频率限制异常
             */
            if($exception instanceof ThrottleRequestsException){
                return failed('请求频率超限!请稍后再试', 400);
            }
        }else{
            $data = $this->notice($request,$exception);
            if($data!==false){
                return failed($data['msg'],$data['code']);
            }
        }

        return parent::render($request, $exception);
    }

    /**
     * Description: 计划任务异常处理
     * Author: Gxs
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @param Exception $e
     */
    public function renderForConsole($output, Exception $e)
    {
        $this->noticeForConsole($output, $e);
        parent::renderForConsole($output, $e);
    }

    /**
     * Description: api预警通知
     * Author: Gxs
     * @param \Illuminate\Http\Request $request
     * @param Exception $exception
     * @return array|bool
     */
    public function notice($request,$exception)
    {
        $env = config('app.env');
        if ('local' != $env && 'Local' != $env) {
            Ding::text('Warning.', [], true, $env);
            $trace = env('TRACE');
            $route = $request->getRequestUri();
            $method = $request->method();
            if($trace){
                $markdown_text = "## Warning \r\n#### **Environment--{$env}**\r\n#### Route:{$route}\r\n#### Method：{$method}\r\n#### Code-**{$exception->getCode()}**\r\n#### File-**{$exception->getFile()}**\r\n#### 行号-**{$exception->getLine()}**\r\n#### Message-**{$exception->getMessage()}**\r\n**{$exception->getTraceAsString()}";
            }else{
                $markdown_text = "## Warning \r\n#### **Environment--{$env}**\r\n#### Route:{$route}\r\n#### Method：{$method}\r\n#### Code-**{$exception->getCode()}**\r\n#### File-**{$exception->getFile()}**\r\n#### 行号-**{$exception->getLine()}**\r\n#### Message-**{$exception->getMessage()}**";
            }

            Ding::markdown([
                'title' => '预警啦!!!',
                'text' => $markdown_text,
            ], [], true, $env);

            $data = ['msg'=>'服务器错误','code'=>500];
            return $data;

        }
        return false;
    }

    /**
     * Description: 计划任务异常处理预警
     * Author: Gxs
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @param Exception $e
     * @return bool
     */
    public function noticeForConsole($output, $e)
    {
        $env = config('app.env');
        if ('local' != $env && 'Local' != $env) {
            Ding::text('Warning.', [], true, $env);
            $trace = env('TRACE');
            if($trace){
                $markdown_text = "## Warning \r\n#### Environment--{$env}\r\n#### Code-**{$e->getCode()}**\r\n#### File-**{$e->getFile()}**\r\n#### Line-**{$e->getLine()}**\r\n#### Message-**{$e->getMessage()}**\r\n**{$e->getTraceAsString()}";
            }else{
                $markdown_text = "## Warning \r\n#### Environment--{$env}\r\n#### Code-**{$e->getCode()}**\r\n#### File-**{$e->getFile()}**\r\n#### Line-**{$e->getLine()}**\r\n#### Message-**{$e->getMessage()}**";
            }

            Ding::markdown([
                'title' => '预警啦!!!',
                'text' => $markdown_text,
            ], [], true, $env);
        }
        return false;
    }
}
